\defmodule{SubsetOfPointSet}

This container class permits one to select a subset of a point set. 
This is done by selecting a range or providing an array of either
point or coordinate indices.  A typical application of a range selection
is to make the number of points or the dimension finite. It is also 
possible to provide, for example, a random permutation in the selection of
components. It is possible also to take \emph{projections} of coordinates
for selected dimensions. 

Selecting a new subset of points or coordinates overwrites the previous
selection.  The specification of a subset with respect to the points
is independent from selecting a subset with respect to the coordinates.
The number of points and the dimension are adapted
to the current selection and all indices still start from 0,
i.e., the subset works just like an ordinary point set.

%\begin{itemize}
%\item Creation first, extraction later via methods.
%\item Extraction is always with respect to the original \texttt{P} 
%passed to the constructor.
%\end{itemize}

%When creating an iterator, the selected ranges are saved in it.
%Any modification to the range from the \texttt{PointSet} will not
%affect the past iterators but will influence the future ones.
When the points or coordinates ranges are changed, existing iterators
become invalid.  They should be reconstructed or reset to avoid
inconsistencies.

\hpierre{This class does not extend \class{ContainerPointSet}{},
  because its iterators must maintain their own indices in addition
  to having inner iterators.}

\bigskip\hrule\bigskip

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{code}
\begin{hide}
/*
 * Class:        SubsetOfPointSet
 * Description:  Subset of a point set
 * Environment:  Java
 * Software:     SSJ 
 * Copyright (C) 2001  Pierre L'Ecuyer and Universite de Montreal
 * Organization: DIRO, Universite de Montreal
 * @author       
 * @since

 * SSJ is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License (GPL) as published by the
 * Free Software Foundation, either version 3 of the License, or
 * any later version.

 * SSJ is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * A copy of the GNU General Public License is available at
   <a href="http://www.gnu.org/licenses">GPL licence site</a>.
 */
\end{hide}
package umontreal.iro.lecuyer.hups;\begin{hide}

import umontreal.iro.lecuyer.util.PrintfFormat;

 /*Attention: No array index range tests neither for the dimension
   nor for the number of points is performed. This is left to JAVA. */
\end{hide}

public class SubsetOfPointSet extends PointSet \begin{hide} {
   protected PointSet P;                  // Source points
   protected int i_from, i_to, i_index[]; // Limits or lookup for row
   protected int j_from, j_to, j_index[]; // Limits or lookup for column

\end{hide}
\end{code}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsubsection*{Constructor}
\begin{code}

   public SubsetOfPointSet (PointSet P) \begin{hide} {
      this.P = P;
      numPoints = P.getNumPoints();
      dim = P.getDimension();
      i_from = 0;
      i_to = P.getNumPoints();
      j_from = 0;
      j_to = P.getDimension();
   }\end{hide}
\end{code}
 \begin{tabb}
   Constructs a new \class{PointSet}{} object, initially identical to \texttt{P}, 
   and from which a subset of the points and/or a subset of the coordinates 
   is to be extracted.  
% The point set \texttt{P} in unaffected.
 \end{tabb}
\begin{htmlonly}
   \param{P}{point set for which a subset is constructed}
\end{htmlonly}
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsubsection*{Methods}
\begin{code}

   public void selectPointsRange (int from, int to) \begin{hide} {
      if (0 > from || from >= to || to > P.getNumPoints())
         throw new IllegalArgumentException ("Invalid range for points");

      i_index = null;
      i_from = from;
      i_to = to;
      numPoints = to - from;
   }\end{hide}
\end{code}
 \begin{tabb}
   Selects the points numbered from ``\texttt{from}'' to ``\texttt{to - 1}'' from the
   original point set.
 \end{tabb}
\begin{htmlonly}
   \param{from}{index of the point, in the contained point set,
    corresponding to the point 0 of this point set}
   \param{to}{index of the last point taken from the contained point set}
\end{htmlonly}
\begin{code}

   public void selectPoints (int[] pointIndices, int numPoints) \begin{hide} {
      if (numPoints > P.getNumPoints() || numPoints > pointIndices.length)
         throw new IllegalArgumentException ("Number of indices too large");

      i_index = pointIndices;
      this.numPoints = numPoints;
   }\end{hide}
\end{code}
 \begin{tabb}
   Selects the \texttt{numPoints} points whose numbers are provided in the array
   \texttt{pointIndices}.
 \end{tabb}
\begin{htmlonly}
   \param{pointIndices}{array of point indices to be selected}
   \param{numPoints}{number of points in the subset of point set}
\end{htmlonly}
\begin{code}

   public void selectCoordinatesRange (int from, int to) \begin{hide} {
      if (0 > from || from >= to || to > P.getDimension())
         throw new IllegalArgumentException("Invalid column range");

      j_index = null;
      j_from = from;
      j_to = to;
      dim = to - from;
   }\end{hide}
\end{code}
 \begin{tabb}
   Selects the coordinates from ``\texttt{from}'' to ``\texttt{to - 1}'' from the
   original point set.
 \end{tabb}
\begin{htmlonly}
   \param{from}{index of the coordinate, in the contained point set,
    corresponding to the coordinate 0 of each point of this point set}
   \param{to}{index of the last coordinate taken for each point
      from the contained point set}
\end{htmlonly}
\begin{code}

   public void selectCoordinates (int[] coordIndices, int numCoord) \begin{hide} {
      if (numCoord > P.getDimension() || numCoord > coordIndices.length)
         throw new IllegalArgumentException ("Number of indices too large");

      j_index = coordIndices;
      this.dim = numCoord;
   }\end{hide}
\end{code}
 \begin{tabb}
   Selects the \texttt{numCoord} coordinates whose numbers are provided in
   the array \texttt{coordIndices}.
 \end{tabb}
\begin{htmlonly}
   \param{coordIndices}{array of coordinate indices to be selected}
   \param{numCoord}{number of coordinatess for each point in the subset of point set}
\end{htmlonly}
\begin{code}\begin{hide}

   public double getCoordinate (int i, int j) {
      int access_i, access_j;

      // if no range check done: left to JAVA array index check
      
      if (i_index == null) {
         if (i < 0 || i >= numPoints)
            throw new IllegalArgumentException ("Row out of range");
         
         access_i = i + i_from;
      } else 
         access_i = i_index[i];

      if (j_index == null) {
         if (j < 0 || j > dim)
            throw new IllegalArgumentException("Column out of range");
         
         access_j = j + j_from;
      } else 
         access_j = j_index[j];

      return P.getCoordinate (access_i, access_j);
   }

   public PointSetIterator iterator() {
      return new SubsetIterator();
   }

   public String toString() {
      StringBuffer sb = new StringBuffer ("Subset of point set" +
              PrintfFormat.NEWLINE);
      sb.append ("Inner point set information {" + PrintfFormat.NEWLINE);
      sb.append (P.toString());
      sb.append (PrintfFormat.NEWLINE + "}" + PrintfFormat.NEWLINE);

      if (i_index == null)
         sb.append ("Points range from " + i_from + " to " + i_to + "." +
               PrintfFormat.NEWLINE);
      else {
         sb.append ("Point indices: [");
         boolean first = true;
         for (int i = 0; i < numPoints; i++) {
            if (first)
               first = false;
            else
               sb.append (", ");
            sb.append (i_index[i]);
         }
         sb.append ("]" + PrintfFormat.NEWLINE);
      }

      if (j_index == null)
         sb.append ("Coordinates range from " + j_from + " to " + j_to + ".");
      else {
         sb.append ("Coordinate indices: [");
         boolean first = true;
         for (int i = 0; i < dim; i++) {
            if (first)
               first = false;
            else
               sb.append (", ");
            sb.append (j_index[i]);
         }
         sb.append ("]");
      }

      return sb.toString();
   }


   // ***********************************************************

   private class SubsetIterator extends DefaultPointSetIterator {

      private PointSetIterator innerIterator;
/*
      private int i_from;
      private int i_to;
      private int j_from;
      private int j_to;
      private int[] i_index;
      private int[] j_index;
*/

      SubsetIterator() {
         // Since one can change range after construction, we
         // must save the current one.
         //this.i_from = SubsetOfPointSet.this.i_from;
         //this.i_to = SubsetOfPointSet.this.i_to;
         //this.j_from = SubsetOfPointSet.this.j_from;
         //this.j_to = SubsetOfPointSet.this.j_to;

         // Also recopy indices in case one has set the indices,
         // kept the array and modified it after construction.
         //if (SubsetOfPointSet.this.i_index == null)
         //   this.i_index = null;
         //else {
         //   this.i_index = new int[SubsetOfPointSet.this.i_index.length];
         //   System.arraycopy (SubsetOfPointSet.this.i_index, 0,
         //             this.i_index, 0, numPoints);
         //}

         //if (SubsetOfPointSet.this.j_index == null)
         //   this.j_index = null;
         //else {
         //   this.j_index = new int[SubsetOfPointSet.this.j_index.length];
         //   System.arraycopy (SubsetOfPointSet.this.j_index, 0, this.j_index, 0, dim);
         //}

         // Create the inner iterator and set its state according to the subset.
         innerIterator = P.iterator();
         if (i_index == null) {
            if (i_from != 0)
               innerIterator.setCurPointIndex (i_from);
         }
         else {
            if (i_index[0] != 0)
               innerIterator.setCurPointIndex (i_index[0]);
         }

         if (j_index == null) {
            if (j_from != 0)
               innerIterator.setCurCoordIndex (j_from);
         }
         else {
            if (j_index[0] != 0)
               innerIterator.setCurCoordIndex (j_index[0]);
         }
      }

      public void setCurCoordIndex (int j) {
         if (j_index == null)
            innerIterator.setCurCoordIndex (j + j_from);
         else
            innerIterator.setCurCoordIndex (j_index[j]);
         curCoordIndex = j;
      }

      public void resetCurCoordIndex() {
         if (j_index == null) {
            if (j_from == 0)
               innerIterator.resetCurCoordIndex();
            else
               innerIterator.setCurCoordIndex (j_from);
         }
         else {
            if (j_index[0] == 0)
               innerIterator.resetCurCoordIndex();
            else
               innerIterator.setCurCoordIndex (j_index[0]);
         }
         curCoordIndex = 0;
      }

      public double nextCoordinate() {
         if ((curPointIndex >= numPoints) || (curCoordIndex >= dim))
            outOfBounds();
         // The inner iterator could throw an exception.
         // If that happens, e must not alter the current coordinate.
         double coord = 0.0;

         if (j_index == null)
            coord = innerIterator.nextCoordinate();
         else {
            int currentIndex = j_index[curCoordIndex];
            int futureIndex = (curCoordIndex+1) == dim ? 
                              currentIndex+1 : j_index[curCoordIndex+1];
            coord = innerIterator.nextCoordinate();
            if (futureIndex != (currentIndex+1))
               innerIterator.setCurCoordIndex (futureIndex);
         }
         curCoordIndex++;
         return coord;
      }

      public void nextCoordinates (double[] p, int d) {
         if (curPointIndex >= numPoints || curCoordIndex + d > dim)
            outOfBounds();
         if (j_index != null) {
            super.nextCoordinates (p, d);
            return;
         }
         innerIterator.nextCoordinates (p, d);
         curCoordIndex += d;
      }

      public void setCurPointIndex (int i) {
         if (i_index == null)
            innerIterator.setCurPointIndex (i + i_from);
         else
            innerIterator.setCurPointIndex (i_index[i]);
         curPointIndex = i;
         resetCurCoordIndex();
      }

      public void resetCurPointIndex() { 
         if (i_index == null) {
            if (i_from == 0)
               innerIterator.resetCurPointIndex();
            else
               innerIterator.setCurPointIndex (i_from);
         }
         else {
            if (i_index[0] == 0)
               innerIterator.resetCurPointIndex();
            else
               innerIterator.setCurPointIndex (i_index[0]);
         }
         curPointIndex = 0;
         resetCurCoordIndex();
      }

      public int resetToNextPoint() {
         if (i_index == null)
            innerIterator.resetToNextPoint();
         else if (curPointIndex < (numPoints-1))
            innerIterator.setCurPointIndex (i_index[curPointIndex + 1]);
         curPointIndex++;  
         resetCurCoordIndex();
         return curPointIndex;
      }
   }
}\end{hide}
\end{code}

\pierre{Code \`a reviser.}
